1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.apache.tapestry5.internal.model;
16
17 import org.apache.tapestry5.ioc.Location;
18 import org.apache.tapestry5.ioc.Resource;
19 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
20 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
21 import org.apache.tapestry5.ioc.util.IdAllocator;
22 import org.apache.tapestry5.model.*;
23 import org.slf4j.Logger;
24
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30
31
32
33 public final class MutableComponentModelImpl implements MutableComponentModel
34 {
35 private final ComponentModel parentModel;
36
37 private final Resource baseResource;
38
39 private final String componentClassName;
40
41 private final IdAllocator persistentFieldNameAllocator = new IdAllocator();
42
43 private final Logger logger;
44
45 private final boolean pageClass;
46
47 private Map<String, ParameterModel> parameters;
48
49 private Map<String, EmbeddedComponentModel> embeddedComponents;
50
51
52
53
54 private Map<String, String> persistentFields;
55
56 private List<String> mixinClassNames;
57
58 private Map<String, String[]> mixinOrders;
59
60 private boolean informalParametersSupported;
61
62 private boolean mixinAfter;
63
64 private Map<String, String> metaData;
65
66 private Set<Class> handledRenderPhases;
67
68 private Map<String, Boolean> handledEvents;
69
70 private final String libraryName;
71
72 private boolean handleActivationEventContext;
73
74 public MutableComponentModelImpl(String componentClassName, Logger logger, Resource baseResource,
75 ComponentModel parentModel, boolean pageClass, String libraryName)
76 {
77 this.componentClassName = componentClassName;
78 this.logger = logger;
79 this.baseResource = baseResource;
80 this.parentModel = parentModel;
81 this.pageClass = pageClass;
82 this.libraryName = libraryName;
83
84
85 this.handleActivationEventContext = false;
86
87
88
89 if (this.parentModel != null)
90 {
91 for (String name : this.parentModel.getPersistentFieldNames())
92 {
93 persistentFieldNameAllocator.allocateId(name);
94 }
95 }
96 }
97
98 public String getLibraryName()
99 {
100 return libraryName;
101 }
102
103 @Override
104 public String toString()
105 {
106 return String.format("ComponentModel[%s]", componentClassName);
107 }
108
109 public Logger getLogger()
110 {
111 return logger;
112 }
113
114 public Resource getBaseResource()
115 {
116 return baseResource;
117 }
118
119 public String getComponentClassName()
120 {
121 return componentClassName;
122 }
123
124 public void addParameter(String name, boolean required, boolean allowNull, String defaultBindingPrefix,
125 boolean cached)
126 {
127 assert InternalUtils.isNonBlank(name);
128 assert InternalUtils.isNonBlank(defaultBindingPrefix);
129
130 if (parameters == null)
131 {
132 parameters = CollectionFactory.newCaseInsensitiveMap();
133 }
134
135 if (parameters.containsKey(name))
136 {
137 throw new IllegalArgumentException(String.format("Parameter '%s' of component class %s is already defined.", name, componentClassName));
138 }
139
140 ParameterModel existingModel = getParameterModel(name);
141
142 if (existingModel != null)
143 {
144 throw new IllegalArgumentException(String.format("Parameter '%s' of component class %s conflicts with the parameter defined by the %s base class.",
145 name, componentClassName, existingModel.getComponentModel().getComponentClassName()));
146 }
147
148 parameters.put(name, new ParameterModelImpl(this, name, required, allowNull, defaultBindingPrefix, cached));
149 }
150
151 public void addParameter(String name, boolean required, boolean allowNull, String defaultBindingPrefix)
152 {
153
154
155
156
157
158 addParameter(name, required, allowNull, defaultBindingPrefix, false);
159 }
160
161 public ParameterModel getParameterModel(String parameterName)
162 {
163 ParameterModel result = InternalUtils.get(parameters, parameterName);
164
165 if (result == null && parentModel != null)
166 result = parentModel.getParameterModel(parameterName);
167
168 return result;
169 }
170
171 public boolean isFormalParameter(String parameterName)
172 {
173 return getParameterModel(parameterName) != null;
174 }
175
176 public List<String> getParameterNames()
177 {
178 List<String> names = CollectionFactory.newList();
179
180 if (parameters != null)
181 names.addAll(parameters.keySet());
182
183 if (parentModel != null)
184 names.addAll(parentModel.getParameterNames());
185
186 Collections.sort(names);
187
188 return names;
189 }
190
191 public List<String> getDeclaredParameterNames()
192 {
193 return InternalUtils.sortedKeys(parameters);
194 }
195
196 public MutableEmbeddedComponentModel addEmbeddedComponent(String id, String type, String componentClassName,
197 boolean inheritInformalParameters, Location location)
198 {
199
200
201 if (embeddedComponents == null)
202 embeddedComponents = CollectionFactory.newCaseInsensitiveMap();
203 else if (embeddedComponents.containsKey(id))
204 throw new IllegalArgumentException(String.format("Embedded component '%s' has already been defined for component class %s.", id, this.componentClassName));
205
206 MutableEmbeddedComponentModel embedded = new MutableEmbeddedComponentModelImpl(id, type, componentClassName,
207 this.componentClassName, inheritInformalParameters, location);
208
209 embeddedComponents.put(id, embedded);
210
211 return embedded;
212 }
213
214 public List<String> getEmbeddedComponentIds()
215 {
216 List<String> result = CollectionFactory.newList();
217
218 if (embeddedComponents != null)
219 result.addAll(embeddedComponents.keySet());
220
221 if (parentModel != null)
222 result.addAll(parentModel.getEmbeddedComponentIds());
223
224 Collections.sort(result);
225
226 return result;
227 }
228
229 public EmbeddedComponentModel getEmbeddedComponentModel(String componentId)
230 {
231 EmbeddedComponentModel result = InternalUtils.get(embeddedComponents, componentId);
232
233 if (result == null && parentModel != null)
234 result = parentModel.getEmbeddedComponentModel(componentId);
235
236 return result;
237 }
238
239 public String getFieldPersistenceStrategy(String fieldName)
240 {
241 String result = InternalUtils.get(persistentFields, fieldName);
242
243 if (result == null && parentModel != null)
244 result = parentModel.getFieldPersistenceStrategy(fieldName);
245
246 if (result == null)
247 throw new IllegalArgumentException(String.format("No field persistence strategy has been defined for field '%s'.", fieldName));
248
249 return result;
250 }
251
252 public List<String> getPersistentFieldNames()
253 {
254 return persistentFieldNameAllocator.getAllocatedIds();
255 }
256
257 public String setFieldPersistenceStrategy(String fieldName, String strategy)
258 {
259 String logicalFieldName = persistentFieldNameAllocator.allocateId(fieldName);
260
261 if (persistentFields == null)
262 persistentFields = CollectionFactory.newMap();
263
264 persistentFields.put(logicalFieldName, strategy);
265
266 return logicalFieldName;
267 }
268
269 public boolean isRootClass()
270 {
271 return parentModel == null;
272 }
273
274 public void addMixinClassName(String mixinClassName, String... order)
275 {
276 if (mixinClassNames == null)
277 mixinClassNames = CollectionFactory.newList();
278
279 mixinClassNames.add(mixinClassName);
280 if (order != null && order.length > 0)
281 {
282 if (mixinOrders == null)
283 mixinOrders = CollectionFactory.newCaseInsensitiveMap();
284 mixinOrders.put(mixinClassName, order);
285 }
286 }
287
288 public List<String> getMixinClassNames()
289 {
290 List<String> result = CollectionFactory.newList();
291
292 if (mixinClassNames != null)
293 result.addAll(mixinClassNames);
294
295 if (parentModel != null)
296 result.addAll(parentModel.getMixinClassNames());
297
298 Collections.sort(result);
299
300 return result;
301 }
302
303 public void enableSupportsInformalParameters()
304 {
305 informalParametersSupported = true;
306 }
307
308 public boolean getSupportsInformalParameters()
309 {
310 return informalParametersSupported;
311 }
312
313 public ComponentModel getParentModel()
314 {
315 return parentModel;
316 }
317
318 public boolean isMixinAfter()
319 {
320 return mixinAfter;
321 }
322
323 public void setMixinAfter(boolean mixinAfter)
324 {
325 this.mixinAfter = mixinAfter;
326 }
327
328 public void setMeta(String key, String value)
329 {
330 assert InternalUtils.isNonBlank(key);
331 assert InternalUtils.isNonBlank(value);
332 if (metaData == null)
333 metaData = CollectionFactory.newCaseInsensitiveMap();
334
335
336
337 metaData.put(key, value);
338 }
339
340 public void addRenderPhase(Class renderPhase)
341 {
342 assert renderPhase != null;
343 if (handledRenderPhases == null)
344 handledRenderPhases = CollectionFactory.newSet();
345
346 handledRenderPhases.add(renderPhase);
347 }
348
349 public void addEventHandler(String eventType)
350 {
351 if (handledEvents == null)
352 handledEvents = CollectionFactory.newCaseInsensitiveMap();
353
354 handledEvents.put(eventType, true);
355 }
356
357 public String getMeta(String key)
358 {
359 String result = InternalUtils.get(metaData, key);
360
361 if (result == null && parentModel != null)
362 result = parentModel.getMeta(key);
363
364 return result;
365 }
366
367 public Set<Class> getHandledRenderPhases()
368 {
369 Set<Class> result = CollectionFactory.newSet();
370
371 if (parentModel != null)
372 result.addAll(parentModel.getHandledRenderPhases());
373
374 if (handledRenderPhases != null)
375 result.addAll(handledRenderPhases);
376
377 return result;
378 }
379
380 public boolean handlesEvent(String eventType)
381 {
382 if (InternalUtils.get(handledEvents, eventType) != null)
383 return true;
384
385 return parentModel == null ? false : parentModel.handlesEvent(eventType);
386 }
387
388 public String[] getOrderForMixin(String mixinClassName)
389 {
390 final String[] orders = InternalUtils.get(mixinOrders, mixinClassName);
391
392 if (orders == null && parentModel != null)
393 return parentModel.getOrderForMixin(mixinClassName);
394
395 return orders;
396 }
397
398 public boolean isPage()
399 {
400 return pageClass;
401 }
402
403 public void doHandleActivationEventContext()
404 {
405 this.handleActivationEventContext = true;
406 }
407
408 public boolean handleActivationEventContext()
409 {
410 return this.handleActivationEventContext;
411 }
412 }